package com.inforich.app.api.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.inforich.app.api.dto.TransportDTO;
import com.inforich.app.api.service.IAppTransportService;
import com.inforich.app.api.vo.TransportVO;
import com.inforich.app.component.LoginUserApp;
import com.inforich.appManage.service.IContactService;
import com.inforich.carManage.domain.Driver;
import com.inforich.carManage.service.IDriverService;
import com.inforich.common.constant.ProjectConstants;
import com.inforich.common.core.domain.AjaxResult;
import com.inforich.common.enums.BookingEnum;
import com.inforich.common.mybatis.Location;
import com.inforich.common.utils.DictUtils;
import com.inforich.common.utils.JsonUtil;
import com.inforich.common.utils.Utils;
import com.inforich.disposal.domain.DisposalLand;
import com.inforich.disposal.service.IDisposalLandService;
import com.inforich.orderManage.domain.Booking;
import com.inforich.orderManage.domain.Transport;
import com.inforich.orderManage.service.IBookingService;
import com.inforich.orderManage.service.ITransportService;
import com.inforich.system.service.ISysConfigService;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Handler;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @description: some desc
 * @author: HJM
 * @date: 2022/10/31
 */
@Service
public class AppTransportServiceImpl implements IAppTransportService {

  @Autowired
  private ITransportService transportService;
  @Autowired
  private IBookingService bookingService;
  @Autowired
  private IContactService contactService;
  @Autowired
  private IDriverService driverService;
  @Autowired
  private IDisposalLandService disposalLandService;
  @Autowired
  private ISysConfigService sysConfigService;

  @Override
  public TransportVO getInfo(String id) {
    Transport transport = transportService.getTransportById(id);
    Booking booking = bookingService.getBookingById(transport.getBookingId());
    TransportVO vo = new TransportVO();
    BeanUtils.copyProperties(transport, vo);
    vo.setBookingTime(booking.getBookingTime());
    return vo;
  }

  @Override
  public AjaxResult getTransportStatus(LoginUserApp loginUserApp, TransportDTO dto) {
    String bookingId = dto.getBookingId();
    // 当前坐标
    Location currentLocation = dto.getLocation();
    Booking booking = bookingService.getBookingById(bookingId);
    String status = getBookingStatus(booking);
    if (StrUtil.isNotBlank(status)) {
      return AjaxResult.success(JsonUtil.of("status", status));
    }
    Long driverId = contactService.getDriverIdByAppUserId(loginUserApp.getId());
    List<Transport> transportList = transportService.listByBookingIdAndDriverId(booking.getId(),
        driverId);
    if (CollUtil.isEmpty(transportList)) {
      // 超出开始范围
      if (isExceed(booking.getLocation(), currentLocation)) {
        return AjaxResult.success(JsonUtil.of("status", "无法打卡"));
      }
      return AjaxResult.success(JsonUtil.of("status", "开始发车"));
    }
    Transport transport = transportList.get(0);
    if (transport.getEndTime() == null) {
      // 处置厂地址
      DisposalLand disposalLand = disposalLandService.getDisposalLandById(
          booking.getDisposalLandId());
      if (isExceed(disposalLand.getLocation(), currentLocation)) {
        return AjaxResult.success(JsonUtil.of("status", "无法打卡"));
      }
      return AjaxResult.success(JsonUtil.of("status", "运输结束"));
    } else {
      if (isExceed(booking.getLocation(), currentLocation)) {
        return AjaxResult.success(JsonUtil.of("status", "无法打卡"));
      }
      return AjaxResult.success(JsonUtil.of("status", "开始发车"));
    }
  }

  @Override
  public AjaxResult startTransport(LoginUserApp loginUserApp, TransportDTO dto) {
    Booking booking = bookingService.getBookingById(dto.getBookingId());
    String status = getBookingStatus(booking);
    if (StrUtil.isNotBlank(status)) {
      return AjaxResult.error("不可进行开始发车，当前运输单状态为: " + status);
    }
    Long driverId = contactService.getDriverIdByAppUserId(loginUserApp.getId());
    List<Transport> transportList = transportService.listByBookingIdAndDriverId(booking.getId(),
        driverId);
    if (CollUtil.isNotEmpty(transportList) && transportList.get(0).getEndTime() == null) {
      return AjaxResult.error("当前有运输单未结束，不可进行发车操作");
    }

    Driver driver = driverService.getById(driverId);
    Transport transport = new Transport();
    transport.setBookingId(dto.getBookingId());
    transport.setCarNumber(driver.getCarNumber());
    transport.setCarType(
        DictUtils.getDictLabel("car_type_id", String.valueOf(driver.getCarTypeId())));
    transport.setDriverName(driver.getName());
    transport.setDriverPhone(driver.getPhone());
    transport.setVehicleLoad(driver.getVehicleLoad());
    transport.setState(10L);
    transport.setDriverId(driver.getId());
    transport.setTransportCompanyId(booking.getTransportCompanyId());
    transport.setProjectId(booking.getProjectId());
    transport.setDisposalLandId(booking.getDisposalLandId());
    transport.setBeginTime(new Date());
    transport.setBeginLocation(dto.getLocation());
    Boolean isExceed = isExceed(booking.getLocation(), dto.getLocation());
    transport.setBeginLocationExceed(isExceed ? 1 : 0);
    transport.setBeginAddress(dto.getAddress());
    transport.setBeginImage(dto.getImage());
    transportService.insertTransport(transport);
    return AjaxResult.success();
  }

  @Override
  public AjaxResult endTransport(LoginUserApp loginUserApp, TransportDTO dto) {
    Booking booking = bookingService.getBookingById(dto.getBookingId());
    String status = getBookingStatus(booking);
    if (StrUtil.isNotBlank(status)) {
      return AjaxResult.error("不可进行运输结束操作，当前运输单状态为: " + status);
    }
    Long driverId = contactService.getDriverIdByAppUserId(loginUserApp.getId());
    List<Transport> transportList = transportService.listByBookingIdAndDriverId(booking.getId(),
        driverId);
    if (CollUtil.isEmpty(transportList)) {
      return AjaxResult.error("当前没有进行中的运输单，不可进行运输结束操作");
    }
    Transport transport = transportList.get(0);
    if (!ProjectConstants.TRANSPORT_STATE_ING.equals(transport.getState())) {
      return AjaxResult.error("当前没有进行中的运输单，不可进行运输结束操作");
    }
    if (transport.getEndTime() != null) {
      return AjaxResult.error("当前订单已结束，不可进行运输结束操作");
    }
    transport.setEndTime(new Date());
    transport.setEndLocation(dto.getLocation());
    transport.setState(ProjectConstants.TRANSPORT_STATE_COMPLETE);
    transport.setEndAddress(dto.getAddress());
    transport.setEndImage(dto.getImage());

    // 处置厂地址
    DisposalLand disposalLand = disposalLandService.getDisposalLandById(
        booking.getDisposalLandId());
    Boolean isExceed = isExceed(disposalLand.getLocation(), dto.getLocation());
    transport.setEndLocationExceed(isExceed ? 1 : 0);

    transportService.updateTransport(transport);

    return AjaxResult.success();
  }

  /**
   * 获取当前预约单状态，只有在进行中时才能操作运输单
   */
  @Override
  public String getBookingStatus(Booking booking) {
    if (BookingEnum.CONDUCT.getDbData().equals(booking.getState().intValue())) {
      return "";
    }
    return BookingEnum.STATE_MAP.get(booking.getState().intValue());
  }

  /**
   * 是否超出范围(超过2千米就算超出)
   *
   * @param destLocation      目标地址
   * @param transportLocation 运输地址
   */
  private Boolean isExceed(Location destLocation, Location transportLocation) {
    long exceedDistance = 2000L;
    if (destLocation == null || transportLocation == null) {
      return true;
    }
    // 从系统参数中获取配置的打卡距离
    String config = sysConfigService.selectConfigByKey("sys.transport.distance");
    if (StrUtil.isNotBlank(config)) {
      exceedDistance = Long.parseLong(config);
    }
    double lon1 = destLocation.getCoordinates()[0];
    double lat1 = destLocation.getCoordinates()[1];
    double lon2 = transportLocation.getCoordinates()[0];
    double lat2 = transportLocation.getCoordinates()[1];
    double distance = Utils.getDistance(lon1, lat1, lon2, lat2);
    return distance > exceedDistance;
  }
}
